---
title: "Modal"
description: "Display a dialog with custom content that requires attention or provides additional information."
---

import {modalContent} from "@/content/components/modal";

# Modal

Displays a dialog with custom content that requires attention or provides additional information.

<ComponentLinks component="modal" reactAriaHook="useModal" />

---

<CarbonAd/>

## Installation

<PackageManagers
  showGlobalInstallWarning
  commands={{
    cli: "npx heroui-cli@latest add modal",
    npm: "npm install @heroui/modal",
    yarn: "yarn add @heroui/modal",
    pnpm: "pnpm add @heroui/modal",
    bun: "bun add @heroui/modal"
  }}
/>


## Import

HeroUI exports 5 modal-related components:

- **Modal**: The main component to display a modal.
- **ModalContent**: The wrapper of the other modal components.
- **ModalHeader**: The header of the modal.
- **ModalBody**: The body of the modal.
- **ModalFooter**: The footer of the modal.

<ImportTabs
  commands={{
    main: `import {
    Modal,
    ModalContent,
    ModalHeader,
    ModalBody,
    ModalFooter
} from "@heroui/react";`,
    individual:
      `import {
    Modal,
    ModalContent,
    ModalHeader,
    ModalBody,
    ModalFooter
} from "@heroui/modal";`,
  }}
/>

## Usage

When the modal opens:

- Focus is bounded within the modal and set to the first tabbable element.
- Content behind the modal dialog is inert, meaning that users cannot interact with it.

<CodeDemo title="Usage" files={modalContent.usage} />

### Sizes

<CodeDemo title="Sizes" files={modalContent.sizes} />

### Non-dismissible

By default, the modal can be closed by clicking on the overlay or pressing the <Kbd>Esc</Kbd> key.
You can disable this behavior by setting the following properties:

- Set the `isDismissable` property to `false` to prevent the modal from closing when clicking on the overlay.
- Set the `isKeyboardDismissDisabled` property to `true` to prevent the modal from closing when pressing the <Kbd>Esc</Kbd> key.

<CodeDemo title="Non-dissmissible" files={modalContent.nonDismissable} />

### Modal placement

By default the modal is centered on screens larger than `sm` and is at the `bottom` of the screen on mobile. This placement is called `auto`, but
you can change it by using the `placement` prop.

<CodeDemo
  asIframe
  title="Modal placement"
  iframeInitialWidth={320}
  previewHeight="680px"
  iframeSrc="/examples/modal/placement"
  files={modalContent.placement}
/>

> **Note**: The `top-center` and `bottom-center` positions mean that the modal is positioned at the top / bottom of the screen
> on mobile, and at the center of the screen on desktop.

### Overflow scroll

You can use the `scrollBehavior` prop to set the scroll behavior of the modal.

- **inside**: The modal content will be scrollable.
- **outside**: The modal content will be scrollable and the modal will be fixed.

<CodeDemo title="Overflow scroll" files={modalContent.overflow} />

### With Form

The `Modal` handles the focus within the modal content. It means that you can use the modal with
form elements without any problem. The focus returns to the trigger when the modal closes.

<CodeDemo title="With Form" files={modalContent.form} />

> **Note**: You can add the `autoFocus` prop to the first `Input` component to focus it when the modal opens.

### Backdrop

The `Modal` component has a `backdrop` prop to show a backdrop behind the modal. The backdrop can be
either `transparent`, `opaque` or `blur`. The default value is `opaque`.

<CodeDemo title="Backdrop" files={modalContent.backdrop} />

### Custom Backdrop

You can customize the backdrop by using the `backdrop` slot.

<CodeDemo title="Custom Backdrop" files={modalContent.customBackdrop} />

### Custom Motion

Modal offers a `motionProps` property to customize the `enter` / `exit` animation.

<CodeDemo title="Custom Motion" highlightedLines="14-31" files={modalContent.customMotion} />

> Learn more about Framer motion variants [here](https://www.framer.com/motion/animation/#variants).

### Draggable

Try to drag the modal by clicking on the modal header and dragging.

<CodeDemo title="Draggable" files={modalContent.draggable} />

### Draggable Overflow

Setting overflow to `true` allows users to drag the modal to a position where it overflows the viewport.

<CodeDemo title="Draggable Overflow" files={modalContent.draggableOverflow} />

## Slots

- **wrapper**: The wrapper slot of the modal. It wraps the `base` and the `backdrop` slots.
- **base**: The main slot of the modal content.
- **backdrop**: The backdrop slot, it is displayed behind the modal.
- **header**: The header of the modal, it is displayed at the top of the modal.
- **body**: The body of the modal, it is displayed in the middle of the modal.
- **footer**: The footer of the modal, it is displayed at the bottom of the modal.
- **closeButton**: The close button of the modal.

### Custom Styles

You can customize the `Modal` component by passing custom Tailwind CSS classes to the component slots.

<CodeDemo title="Custom Styles" highlightedLines="15-20" files={modalContent.customStyles} />

<Spacer y={4} />

## Data Attributes

`Modal` has the following attributes on the `base` element:

- **data-open**:
  When the modal is open. Based on modal state.
- **data-dismissable**:
  When the modal is dismissable. Based on `isDismissable` prop.

<Spacer y={4} />

## Accessibility

- Content outside the modal is hidden from assistive technologies while it is open.
- The modal optionally closes when interacting outside, or pressing the <Kbd>Esc</Kbd> key.
- Focus is moved into the modal on mount, and restored to the trigger element on unmount.
- While open, focus is contained within the modal, preventing the user from tabbing outside.
- Scrolling the page behind the modal is prevented while it is open, including in mobile browsers.

<Spacer y={4} />

## API

### Modal Props

<APITable
  data={[
    {
      attribute: "children*",
      type: "ReactNode",
      description: "The content of the modal. It's usually the `ModalContent`.",
      default: "-"
    },
    {
      attribute: "size",
      type: "xs | sm | md | lg | xl | 2xl | 3xl | 4xl | 5xl | full",
      description: "The modal size. This changes the modal `max-width` and `height` (full).",
      default: "md"
    },
    {
      attribute: "radius",
      type: "none | sm | md | lg",
      description: "The modal border radius.",
      default: "lg"
    },
    {
      attribute: "shadow",
      type: "none | sm | md | lg",
      description: "The modal shadow.",
      default: "lg"
    },
    {
      attribute: "backdrop",
      type: "transparent | opaque | blur",
      description: "The modal backdrop type.",
      default: "opaque"
    },
    {
      attribute: "scrollBehavior",
      type: "normal | inside | outside",
      description: "The modal scroll behavior.",
      default: "normal"
    },
    {
      attribute: "placement",
      type: "auto | top | center | bottom",
      description: "The modal position.",
      default: "auto"
    },
    {
      attribute: "isOpen",
      type: "boolean",
      description: "Whether the modal is open by default (controlled).",
      default: "-"
    },
    {
      attribute: "defaultOpen",
      type: "boolean",
      description: "Whether the modal is open by default (uncontrolled).",
      default: "-"
    },
    {
      attribute: "isDismissable",
      type: "boolean",
      description: "Whether the modal can be closed by clicking on the overlay or pressing the Esc key.",
      default: "true"
    },
    {
      attribute: "isKeyboardDismissDisabled",
      type: "boolean",
      description: "Whether pressing the Esc key to close the modal should be disabled.",
      default: "false"
    },
    {
      attribute: "shouldBlockScroll",
      type: "boolean",
      description: "Whether the modal should block the scroll of the page on open.",
      default: "true"
    },
    {
      attribute: "hideCloseButton",
      type: "boolean",
      description: "Whether to hide the modal close button.",
      default: "false"
    },
    {
      attribute: "closeButton",
      type: "ReactNode",
      description: "Custom close button to display on top right corner.",
      default: "-"
    },
    {
      attribute: "motionProps",
      type: "MotionProps",
      description: "The props to modify the framer motion animation. Use the `variants` API to create your own animation.",
      default: "-"
    },
    {
      attribute: "portalContainer",
      type: "HTMLElement",
      description: "The container element in which the overlay portal will be placed.",
      default: "document.body"
    },
    {
      attribute: "disableAnimation",
      type: "boolean",
      description: "Whether the modal should not have animations.",
      default: "false"
    },
    {
      attribute: "classNames",
      type: "Partial<Record<'wrapper' | 'base' | 'backdrop' | 'header' | 'body' | 'footer' | 'closeButton', string>>",
      description: "Allows to set custom class names for the modal slots.",
      default: "-"
    }
  ]}
/>

### Modal Events

<APITable
  data={[
    {
      attribute: "onOpenChange",
      type: "(isOpen: boolean) => void",
      description: "Handler that is called when the modal's open state changes.",
      default: "-"
    },
    {
      attribute: "onClose",
      type: "() => void",
      description: "Handler that is called when the modal is closed.",
      default: "-"
    }
  ]}
/>

<Spacer y={4} />

### Modal types

#### Motion Props

```ts
export type MotionProps = HTMLMotionProps<"div">; // @see https://www.framer.com/motion/
```
